package freelists
{
	import flash.display.*;
	import flash.events.*;
	import flash.geom.*;
	import flash.system.*;
	import flash.text.*;
	import flash.utils.*;
	
	public class FreeListTest extends Sprite
	{
		private var __logger:TextField = new TextField();
		
		public function FreeListTest()
		{
			__logger.autoSize = TextFieldAutoSize.LEFT;
			addChild(__logger);
			
			const NUM_COLORS:int = 1000000;
			log("------Unallocated------");
			test(NUM_COLORS);
			preAllocate(NUM_COLORS);
			log("-----Pre-allocated-----");
			test(NUM_COLORS);
		}
		
		private function preAllocate(numColors:int): void
		{
			var i:int;
			var tempLL:Vector.<Color4LinkedList> = new Vector.<Color4LinkedList>(numColors);
			for (i = 0; i < numColors; ++i)
			{
				tempLL[i] = Color4LinkedList.getColor();
			}
			for (i = 0; i < numColors; ++i)
			{
				Color4LinkedList.freeColor(tempLL[i]);
			}
			var tempV:Vector.<Color4Vector> = new Vector.<Color4Vector>(numColors);
			for (i = 0; i < numColors; ++i)
			{
				tempV[i] = Color4Vector.getColor();
			}
			for (i = 0; i < numColors; ++i)
			{
				Color4Vector.freeColor(tempV[i]);
			}
		}
		
		private function test(numColors:int): void
		{
			var cll:Color4LinkedList;
			var cv:Color4Vector;
			var i:int;
			
			// Test with pre-allocated linked list-based free list
			var beforeTime:int = getTimer();
			for (i = 0; i < numColors; ++i)
			{
				cll = Color4LinkedList.getColor();
			}
			var afterTime:int = getTimer();
			log("Allocation from linked list-based free list: " + (afterTime - beforeTime));
			
			// Test with vector-based free list
			beforeTime = getTimer();
			for (i = 0; i < numColors; ++i)
			{
				cv = Color4Vector.getColor();
			}
			afterTime = getTimer();
			log("Allocation from vector-based free list: " + (afterTime - beforeTime));
			
			// Test with direct allocation
			beforeTime = getTimer();
			for (i = 0; i < numColors; ++i)
			{
				cll = new Color4LinkedList();
			}
			afterTime = getTimer();
			log("Direct allocation: " + (afterTime - beforeTime));
		}
		
		private function log(msg:*): void
		{
			__logger.appendText(msg + "\n");
		}
	}
}
class Color4LinkedListNode
{
	public var c:Color4LinkedList;
	public var next:Color4LinkedListNode;
}
class Color4LinkedList
{
	private static var __freeList:Color4LinkedListNode;
	
	public var a:Number;
	public var r:Number;
	public var g:Number;
	public var b:Number;
	
	public function Color4LinkedList(a:Number = 0.0, r:Number = 0.0, g:Number = 0.0, b:Number = 0.0)
	{
		this.a = a;
		this.r = r;
		this.g = g;
		this.b = b;
	}
	
	public static function getColor(a:Number = 0.0, r:Number = 0.0, g:Number = 0.0, b:Number = 0.0): Color4LinkedList
	{
		// Already have one, take the head
		if (__freeList)
		{
			var ret:Color4LinkedList = __freeList.c;
			ret.a = a;
			ret.r = r;
			ret.g = g;
			ret.b = b;
			__freeList = __freeList.next;
			return ret;
		}
		// Have none, make new
		return new Color4LinkedList(a, r, g, b);
	}
	
	public static function freeColor(c:Color4LinkedList): void
	{
		// Add to the head
		var node:Color4LinkedListNode = new Color4LinkedListNode();
		node.c = c;
		node.next = __freeList;
		__freeList = node;
	}
}
class Color4Vector
{
	private static var __freeList:Vector.<Color4Vector> = new Vector.<Color4Vector>();
	
	public var a:Number;
	public var r:Number;
	public var g:Number;
	public var b:Number;
	
	public function Color4Vector(a:Number = 0.0, r:Number = 0.0, g:Number = 0.0, b:Number = 0.0)
	{
		this.a = a;
		this.r = r;
		this.g = g;
		this.b = b;
	}
	
	public static function getColor(a:Number = 0.0, r:Number = 0.0, g:Number = 0.0, b:Number = 0.0): Color4Vector
	{
		// Already have one, take the head
		var freeList:Vector.<Color4Vector> = __freeList;
		if (freeList.length > 0)
		{
			var endIndex:int = freeList.length-1;
			var ret:Color4Vector = freeList[endIndex];
			freeList.length = endIndex;
			ret.a = a;
			ret.r = r;
			ret.g = g;
			ret.b = b;
			return ret;
		}
		// Have none, make new
		return new Color4Vector(a, r, g, b);
	}
	
	public static function freeColor(p:Color4Vector): void
	{
		__freeList.push(p);
	}
}